﻿// author : David Janacek, dj-soft@seznam.cz, 2013-12-13
// company: Asseco Solution, a.s. CZ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace Noris.LCS.AIDCCodes
{
    public class CodeControl : Control
    {
        #region Konstrukce a privátní proměnné
        /// <summary>
        /// Create a new CodeControl object
        /// </summary>
        public CodeControl()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this._Init();
            this.Paint += new PaintEventHandler(_Paint);
            this.SizeChanged += new EventHandler(_SizeChanged);
        }
        private void _Init()
        {
            this._CodeType = CodeType.EAN13;
            this._WhiteColor = Color.White;
            this._BlackColor = Color.Black;
            this._LabelVisible = true;
            this._Time = new System.Diagnostics.Stopwatch();
            this._TimeFreq = (decimal)System.Diagnostics.Stopwatch.Frequency;
        }
        private void _SizeChanged(object sender, EventArgs e)
        {
            this.Refresh();
        }
        /// <summary>
        /// Raise TimeChanged event.
        /// </summary>
        protected virtual void OnTimeChanged()
        {
            if (this.TimeChanged != null)
                this.TimeChanged(this, EventArgs.Empty);
        }
        private System.Diagnostics.Stopwatch _Time;
        private decimal _TimeFreq;
        #endregion
        #region Prepare matrix, Paint matrix
        private void _PrepareMatrix()
        {
            this._PrepareMatrix(this.Text, true);
        }
        private void _PrepareMatrix(string text, bool force)
        {
            if (text == null) text = "";

            if (this._Matrix != null && this._Matrix.Content != null && text == this._Matrix.Content && !force)
                return;

            this._Matrix = null;
            this._Error = null;
            this._LastEncodeTime = 0m;

            if (this._CodeType != AIDCCodes.CodeType.None)
            {
                this._Time.Restart();
                try
                {
                    this._Matrix = Noris.LCS.AIDCCodes.Common.CodeEncoder.Encode(text, this._CodeType);
                }
                catch (Exception exc)
                {
                    this._Error = exc.Message;
                }
                this._LastEncodeTime = this._GetCurrentTime();
            }
        }
        private void _Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(this.BackColor);
            this._PrepareMatrix(this.Text, false);

            this._Time.Restart();

            if (this._Matrix != null)
                this._Matrix.PaintCodeTo(e.Graphics, this.ClientRectangle, this._WhiteColor, this._BlackColor, this._LabelColor, this._LabelVisible);
            else if (this._Error != null)
                this._PaintTextTo(e.Graphics, this.ClientRectangle, this._Error);

            this._LastPaintTime = this._GetCurrentTime();

            this.OnTimeChanged();
        }
        private void _PaintTextTo(Graphics graphics, Rectangle rectangle, string text)
        {
            using (SolidBrush brush = new SolidBrush(this.ForeColor))
            {
                StringFormat sf = new StringFormat(StringFormatFlags.FitBlackBox);
                SizeF clientSize = this.ClientSize;
                SizeF textSize = graphics.MeasureString(text, this.Font, clientSize, sf);
                float x = (textSize.Width < clientSize.Width ? (clientSize.Width - textSize.Width) / 2f : 0f);
                float y = (textSize.Height < clientSize.Height ? (clientSize.Height - textSize.Height) / 2f : 0f);
                float w = (textSize.Width < clientSize.Width ? textSize.Width : clientSize.Width);
                float h = (textSize.Height < clientSize.Height ? textSize.Height : clientSize.Height);
                RectangleF textArea = new RectangleF(x, y, w, h);
                graphics.DrawString(text, this.Font, brush, textArea, sf);
            }
        }
        /// <summary>
        /// Zastaví timer a vrátí dosud uplynulý čas v sekundách
        /// </summary>
        /// <returns></returns>
        private decimal _GetCurrentTime()
        {
            this._Time.Stop();
            long ticks = this._Time.ElapsedTicks;
            return (decimal)ticks / this._TimeFreq;
        }
        #endregion
        #region Public property
        /// <summary>
        /// Content of barcode
        /// </summary>
        [Description("Content of code")]
        [Category("AIDC code")]
        public override string Text
        {
            get { return base.Text; }
            set
            {
                this._PrepareMatrix(value, false);
                base.Text = value;
                this.Refresh();
            }
        }
        /// <summary>
        /// Code type
        /// </summary>
        [Description("Code type")]
        [Category("AIDC code")]
        public CodeType CodeType
        {
            get { return this._CodeType; }
            set
            {
                this._CodeType = value;
                this._PrepareMatrix();
                this.Refresh();
            }
        }
        /// <summary>
        /// Color for White points
        /// </summary>
        [Description("Color for White points")]
        [Category("AIDC code")]
        public Color WhiteColor
        {
            get { return this._WhiteColor; }
            set
            {
                this._WhiteColor = value;
                this.Refresh();
            }
        }
        /// <summary>
        /// Color for Black points
        /// </summary>
        [Description("Color for Black points")]
        [Category("AIDC code")]
        public Color BlackColor
        {
            get { return this._BlackColor; }
            set
            {
                this._BlackColor = value;
                this.Refresh();
            }
        }
        /// <summary>
        /// Color for Label
        /// </summary>
        [Description("Color for Label")]
        [Category("AIDC code")]
        public Color LabelColor
        {
            get { return this._LabelColor; }
            set
            {
                this._LabelColor = value;
                this.Refresh();
            }
        }
        /// <summary>
        /// Show text label in code
        /// </summary>
        [Description("Show text label in code")]
        [Category("AIDC code")]
        public bool LabelVisible
        {
            get { return this._LabelVisible; }
            set
            {
                this._LabelVisible = value;
                this.Refresh();
            }
        }
        /// <summary>
        /// Last encode time (in seconds)
        /// </summary>
        [Description("Last encode time (in seconds)")]
        [Category("AIDC code")]
        public decimal LastEncodeTime
        {
            get { return this._LastEncodeTime; }
        }
        /// <summary>
        /// Last paint time (in seconds)
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Last paint time (in seconds)")]
        [Category("AIDC code")]
        public decimal LastPaintTime
        {
            get { return this._LastPaintTime; }
        }
        /// <summary>
        /// Occurs whenever values LastEncodeTime or LastPaintTime changed.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Occurs whenever values LastEncodeTime or LastPaintTime changed")]
        [Category("AIDC code")]
        public event EventHandler TimeChanged;
        /// <summary>
        /// Matrice bodů kódu
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        public Noris.LCS.AIDCCodes.Common.CodeMatrix Matrix { get { return this._Matrix; } }
        private CodeType _CodeType;
        private Color _WhiteColor;
        private Color _BlackColor;
        private Color _LabelColor;
        private bool _LabelVisible;
        private decimal _LastEncodeTime;
        private decimal _LastPaintTime;
        private Noris.LCS.AIDCCodes.Common.CodeMatrix _Matrix;
        private string _Error;
        #endregion
        #region Static services
        /// <summary>
        /// Return true when specified code type can be encoded (exists appropriate encoder).
        /// </summary>
        /// <param name="codeType"></param>
        /// <returns></returns>
        public static bool CanProcessCodeType(CodeType codeType)
        {
            return Common.CodeEncoder.CanEncode(codeType);
        }
        #endregion
    }
}
